import {
  defaultOptions,
  viewSuffix,
  controlSuffix,
  topicMsg,
  TOPIC_SUFFIX,
  EVENT_CONFIG_MSG,
  EVENT_INTI_CONFIG,
  EVETN_CONTROL_CONFIG_MSG,
} from "../constant";
import config from "../../../config";
import { event } from "./event";
import MqttClient from "../mqttClient";
import { storage } from "./utils";
class CommunicationRtc {
  clientName = "webrtc";
  handlers = {};
  peers = [];
  data = {
    publish: {
      topic: "sgb",
      qos: 0,
    },
    // 订阅主题
    subscription: {
      topic: "sgb",
      qos: 0,
    },
  };

  constructor(id, options) {
    MqttClient.createClient().then((client) => {
      this.client = client;
      options.onConnect && options.onConnect(this);
      this.onMessage();
    });

    this.id = id;
    this.options = { ...defaultOptions, ...options };

    this.username = `${TOPIC_SUFFIX}_${+new Date()}_${this.options.isControl ? controlSuffix : viewSuffix}`;
    this.topicMsg = topicMsg(this.id);
    this.topicState = `${TOPIC_SUFFIX}/${this.id}/webrtc`;

    this.init();
  }

  init() {
    if (this.options.isControl) {
      return;
    }
    // this.peer = new RTCPeerConnection();
    // this.createDatachannel(this.peer);
    // this.peerEvent(this.peer);

    window.addEventListener("beforeunload", () => {
      this.destroy();
    });
  }

  peerEvent(peer) {
    peer.ontrack = (e) => {
      if (e && e.streams) {
        console.log(e.streams[0]);
      }
    };
    peer.onicecandidate = (e) => {
      if (e.candidate) {
        this.send({
          payload: {
            type: "offer_ice",
            iceCandidate: e.candidate,
            toname: peer.username,
          },
        });
      }
    };

    peer.ondatachannel = (event) => {
      var channel = event.channel;
      channel.onopen = () => {
        console.log("数据通道打开，可以发送数据了！");
        peer.channel = channel;
        this.dispatchInitConfigMessage();
      };
      channel.onmessage = (event) => {
        console.log(event.data);
        this.dispatchMessage(event);
      };
    };

    peer.onconnectionstatechange = (event) => {
      console.log(`连接状态改变${peer.username}-->`, event.target.connectionState);
      if (event.target.connectionState === "failed") {
        if (this.options.isControl) {
          let peerObj = this.peers.find((item) => item.username === peer.username);

          peerObj.peer.close();
          peerObj = null;
          this.peers = this.peers.filter((item) => item.username === peer.username);
        } else {
        }
      }
    };
  }

  doSubscribe() {
    return new Promise((resolve, reject) => {
      const { qos } = this.data.subscription;
      this.client.subscribe(this.topicState, { qos }, (error) => {
        if (error) {
          console.log("Subscribe to topics error", error);
          reject(error);
          return;
        }
        resolve();
      });
    });
  }

  async onMessage() {
    this.client.on("message", async (topic, message) => {
      const data = JSON.parse(message);
      if (data.username === this.username) {
        // 接收的是自己的消息就忽略了。
        return;
      }
      console.log(`from topic ${topic}`);

      const { type, sdp, iceCandidate, msg, username, toname, isControl } = data;

      console.log(`form username ${username} type is ${type} to username ${toname}, I is ${this.username}`);

      if (type === "online") {
        this.createRTCPeerConnection(data);
      }

      if (type === "offer_ice" && toname === this.username) {
        this.peers.forEach((peerobj) => {
          peerobj.peer.addIceCandidate(iceCandidate);
        });
      }

      if (type === "offer" && toname === this.username) {
        this.createRTCPeerConnection(data);
      }

      if (type === "answer" && toname === this.username) {
        try {
          await this.setRemoteDescription(username, data);
        } catch (error) {
          console.log("error-->", error);
        }
      }
    });
  }

  async check(resolve) {
    this.resolve = resolve;

    try {
      await this.doSubscribe();
      if (this.options.isControl) {
        // 控制端上线消息发送
        await this.send({
          payload: {
            type: "online",
            msg: "控制端大哥来了，都向我发offer邀请呀！",
          },
        });
        return;
      } else {
        // 放映端直接发offer
        await this.send({
          payload: {
            type: "online",
            msg: "放映端来了，都向我发offer邀请呀！",
          },
        });
      }
    } catch (error) {
      console.log("error-->", error);
    }
  }

  /**
   * 发布消息
   * @param {} topic 主题
   * @param {} retain 是否保留信息
   * @param {} payload 消息内容
   */
  send({ payload, retain = false }) {
    return new Promise((resolve, reject) => {
      const { qos } = this.data.publish;
      payload = {
        ...payload,
        isControl: this.options.isControl,
        username: this.username,
      };

      const json = JSON.stringify(payload);
      this.client.publish(this.topicState, json, { qos, retain }, (error) => {
        if (error) {
          return reject();
        }
        return resolve();
      });
    });
  }

  async sendOffer(peer, payload = {}) {
    try {
      const offer = await peer.createOffer();
      await peer.setLocalDescription(offer);
      await this.send({
        payload: {
          ...offer,
          toname: peer.username,
          ...payload,
        },
      });
    } catch (error) {}
  }

  doPublishConfig(config) {
    const payload = JSON.stringify({
      config,
      id: this.id,
      isControl: this.options.isControl,
      username: this.username,
      time: Date.now(),
    });

    if (this.options.isControl) {
      storage.set(topicMsg(this.id), payload);
      this.peers.forEach((peerobj) => {
        try {
          // 只给通道打开的发
          if (peerobj.peer?.dataChannel.readyState === "open") {
            peerobj.peer?.dataChannel?.send(payload);
          }
        } catch (error) {
          console.log("error-->", error);
        }
      });
    } else {
      this.peer.dataChannel.send(payload);
    }
  }

  createDatachannel(peer) {
    try {
      const dataChannel = peer.createDataChannel("dataChannel", {
        ordered: true,
        reliable: true,
        maxRetransmits: 50,
      });
      peer.dataChannel = dataChannel;

      this.dataChannelEvents(peer);
    } catch (dce) {
      console.log("dc established error: " + dce.message);
    }
  }

  dataChannelEvents(peer) {
    const channel = peer.dataChannel;
    channel.onopen = () => {
      console.log("Datachannel opened, current stateis :\n" + channel.readyState);

      this.dispatchInitConfigMessage();
    };

    //数据接受处理
    channel.onmessage = (event) => {
      this.dispatchMessage(event);
    };

    channel.onerror = (err) => {
      console.log("Datachannel Error: " + err);
    };

    channel.onclose = () => {
      console.log(`DataChannel is closed --> ${peer.username}`);
      if (this.options.isControl) {
        this.peers = this.peers.filter((item) => {
          if (item.username === peer.username) {
            peer.close();
          }
          return item.username !== peer.username;
        });
      }
    };

    channel.onbufferedamountlow = (ev) => {
      // console.log("onbufferedamountlow", ev);
    };
  }

  destroy() {
    if (this.options.isControl) {
      this.peers.forEach((obj) => obj.peer.close());
    } else {
      this.peer.close();
    }
  }

  createRTCPeerConnection(data) {
    const { username, isControl, type } = data;
    if (this.peers.findIndex((item) => item.username == username) > 0) return;
    const peer = new RTCPeerConnection();
    peer.username = username;
    this.createDatachannel(peer);
    this.peerEvent(peer);
    this.peers.push({
      peer,
      username,
      isControl,
    });

    if (type === "online") {
      this.sendOffer(peer, { toname: username });
    }

    if (type === "offer") {
      this.setRemoteDescription(username, data);
    }
  }

  async setRemoteDescription(username, data) {
    try {
      const { type, sdp } = data;
      const obj = this.peers.find((obj) => obj.username === username);

      const offerSdp = new RTCSessionDescription({ type, sdp });
      await obj.peer.setRemoteDescription(offerSdp);
      if (type !== "answer") {
        const answer = await obj.peer.createAnswer();
        await this.send({ payload: { ...answer, toname: username } });
        await obj.peer.setLocalDescription(answer);
      }
      this.dispatchResolve();
    } catch (error) {
      console.log("error-->", error);
    }
  }

  dispatchMessage(event) {
    if (event.data && typeof event.data === "string") {
      const data = JSON.parse(event.data);
      this.dispatch(EVENT_CONFIG_MSG, data);
      if (data.isControl && data.username !== this.username) {
        this.dispatch(EVETN_CONTROL_CONFIG_MSG, data);
        storage.set(topicMsg(this.id), event.data);
      }
    }
  }

  dispatchInitConfigMessage() {
    if (!this.options.isControl) return;
    let cconfig = config;
    const localJson = storage.get(topicMsg(this.id));
    if (localJson && typeof localJson === "string") {
      cconfig = JSON.parse(localJson).config;
    }
    this.dispatch(EVENT_INTI_CONFIG, { config: cconfig });
  }

  dispatchResolve() {
    this.resolve(this);
    this.resolve.isExecute = true;
  }
}

CommunicationRtc.prototype.dispatch = event.dispatch;
CommunicationRtc.prototype.on = event.on;

export default CommunicationRtc;
